package org.infodavid.common.reflect;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * The Class FieldUtil.
 */
@SuppressWarnings("rawtypes")
public final class FieldUtil {

	/** The Constant log. */
	@SuppressWarnings("unused")
	private static final Log LOGGER = LogFactory.getLog(FieldUtil.class);// NOPMD

	/** The singleton. */
	private static WeakReference<FieldUtil> singleton = null;

	/**
	 * returns the singleton.
	 * @return the singleton
	 */
	public static FieldUtil getInstance() {
		if (singleton == null || singleton.get() == null) {
			singleton = new WeakReference<FieldUtil>(new FieldUtil());
		}

		return singleton.get();
	}

	/**
	 * Instantiates a new reflect util.
	 */
	private FieldUtil() {
		super();
	}

	/**
	 * Filter.
	 * @param filter the filter
	 * @param methods the methods
	 * @return the method[]
	 */
	public Method[] filter(final IMethodFilter filter, final Method... methods) {
		final List<Method> results = new ArrayList<Method>();

		if (methods != null) {
			if (filter == null) {
				for (final Method method : methods) {
					results.add(method);
				}
			}
			else {
				for (final Method method : methods) {
					if (filter.accept(method)) {
						results.add(method);
					}
				}
			}
		}

		return results.toArray(new Method[results.size()]);
	}

	/**
	 * Gets the fields.
	 * @param clazz the class
	 * @param filter the filter
	 * @return the fields
	 */
	public Map<String,Field> getFields(final Class clazz, final IFieldFilter filter) {
		Class current = clazz;
		final Map<String,Field> results = new HashMap<String,Field>();
		Field[] fields;
		Field field;
		int i;

		while (current != null) {
			try {
				fields = current.getDeclaredFields();
				i = 0;

				if (fields != null) {
					while (i < fields.length) {
						field = fields[i++];

						if (filter == null || filter.accept(field)) {
							if (!results.containsKey(field.getName())) {
								results.put(field.getName(), field);
							}
						}
					}
				}
			}
			catch (final SecurityException e) {}

			// not found, search in the super class
			current = current.getSuperclass();
		}

		return results;
	}
}
